#include <QtGui>
//#include <QByteArray>

#include "QtStra2.h"
#include "QtStra_InstTableDelegate.h"
#include "QtStra_InstEdit.h"



QtStra2::QtStra2(QDockWidget* instDock, QDockWidget* strategyDock, QTabWidget::TabPosition pos, QWidget *parent): QTabWidget(parent)
{
	//set parent property
	setTabPosition(pos);

	m_xmlfile = "strategy2_userdata.xml";

	m_xml = new QtStraXml( (char*)m_xmlfile.c_str() );

	//set child widget property
	CreateInstInfo(instDock);

	CreateStrategyInfo(strategyDock);

	



}




void QtStra2::CreateInstInfo(QDockWidget* instDock)
{
	//save StrategyDock
	m_instDock = instDock;


	//Create Strategy Table 
	{
		
		//init with row and columne cnt;
		m_instTable = new QTableWidget();
		m_instTable->setItemDelegate(new QtStraInstTableDelegate);
		m_instTable->setSelectionBehavior(QAbstractItemView::SelectRows);
		m_instTable->setAlternatingRowColors(true);

	
				
	}


	//Create spliterBtn to be pushed into dockSplitter
	QSplitter* spliterBtn1 = new QSplitter(Qt::Horizontal);
	QSplitter* spliterBtn2 = new QSplitter(Qt::Horizontal);
	{
		m_ctlBtn = new QPushButton(tr("Start"));
		m_editBtn = new QPushButton(tr("Edit"));
		m_readXmlBtn = new QPushButton(tr("ReadXml"));
		m_writeXmlBtn = new QPushButton(tr("WriteXml"));
		connect(m_ctlBtn, SIGNAL(clicked()), this, SLOT(OnctlBtnClicked()));
		connect(m_editBtn, SIGNAL(clicked()), this, SLOT(OneditBtnClicked()));
		connect(m_readXmlBtn, SIGNAL(clicked()), this, SLOT(OnreadxmlBtnClicked()));
		connect(m_writeXmlBtn, SIGNAL(clicked()), this, SLOT(OnwritexmlBtnClicked()));
		

		spliterBtn1->addWidget(m_ctlBtn);
		spliterBtn1->addWidget(m_editBtn);
		spliterBtn2->addWidget(m_readXmlBtn);
		spliterBtn2->addWidget(m_writeXmlBtn);

		
	}




	//Create dockSplitter to be pushed into dockWidget
	{

		m_instSplitter = new QSplitter(Qt::Vertical);
		m_instSplitter->addWidget(m_instTable);
		m_instSplitter->addWidget(spliterBtn1);
		m_instSplitter->addWidget(spliterBtn2);
		m_instSplitter->setStretchFactor(0, 1);
	}



}


void QtStra2::CreateStrategyInfo(QDockWidget* strategyDock)
{

	m_strategyDock = strategyDock;

	m_strategyinfo = new QtStraStrategyInfo();

}





void QtStra2::OnUpdateInstDockAndStrategyDock()
{
	//update m_instDock
	{
		//QSplitter* child = static_cast<QSplitter*>(m_strategyDock->widget());
		QWidget* child = (m_instDock->widget());

		if (child)
		{
			child->hide();
		}

		m_instDock->setWindowTitle(tr("Inst2_Info"));
		m_instDock->setWidget(m_instSplitter);
	}

	//update strategyDock
	{
		QWidget* child = /*static_cast<QtStraStrategyInfo*>*/(m_strategyDock->widget());

		if (child)
		{
			child->hide();
		}

		m_strategyDock->setWindowTitle(tr("Strategy2_Info"));
		m_strategyDock->setWidget(m_strategyinfo);
	}



}

void QtStra2::CreateThread()
{
	CStrategyUser2* pStrategy = new CStrategyUser2("strategy_user2_thread1");

	if (pStrategy)
	{
		//create thread
		m_thread = new QtStraThread(pStrategy, this);

		if (m_thread)
		{
			connect(m_thread->FrameEvent(), SIGNAL(SignalInit(BarSeries*, BarData*)),
				this, SLOT(OnSlotInit(BarSeries*, BarData*)), Qt::BlockingQueuedConnection);

			connect(m_thread->FrameEvent(), SIGNAL(SignalDestroy(BarInfo*)),
				this, SLOT(OnSlotDestroy(BarInfo*)), Qt::BlockingQueuedConnection);

			
			connect(m_thread->StrategySys(), SIGNAL(SignalSysMd(BarData*)),
				this, SLOT(OnSlotSysMd(BarData*)));




			m_thread->Start();
		}
		else
			pantheios::log_ERROR("[CreateThread] m_thread init failed");

		
	}
	else
		pantheios::log_ERROR("[CreateThread] pStrategy init failed");

	
	

}

void QtStra2::DestroyThread()
{
	if (m_thread)
	{
		delete m_thread;
		m_thread = NULL;
	}
	
}

void QtStra2::OnDestroyAllBars()
{
	/*********************Set m_instTable unchecked*********************************/

	////get count
	//int rowcnt = m_instTable->rowCount();
	//int colcnt = m_instTable->columnCount();
	////
	////from every row
	//for (int rowIndex = 0; rowIndex < rowcnt; rowIndex++)
	//{
	//	Qt::CheckState c = m_instTable->item(rowIndex, 0)->checkState();

	//	//if checked
	//	if (Qt::Checked == c)
	//		m_instTable->item(rowIndex, 0)->setCheckState(Qt::Unchecked);

	//}

	m_stra2thd1_vbarrltold = m_stra2thd1_vbarrltnew;

	m_stra2thd1_vbarrltnew.clear();

	/**********************************************************************************************/

	/*********************StartCtl*********************************/

	StartCtl(TimerFire_namespace::appreinitfiretimer);

	/**********************************************************************************************/
}

void QtStra2::OnReinitAllBars()
{
	//-------------2. recover all data from m_stra2thd1_vbarrltold-----------------------------------------------

	//typedef vector<Stra2Related>::iterator it_vstra1;
	//for (it_vstra1 itold = m_stra2thd1_vbarrltold.begin(); itold != m_stra2thd1_vbarrltold.end(); itold++)
	//{
	//	BarInfo* poldbar = &((*itold).bar);
	//	bool bfound = false;



	//	int rowcnt = m_instTable->rowCount();
	//	int colcnt = m_instTable->columnCount();
	//	//
	//	//from every row int m_instTable
	//	for (int rowIndex = 0; rowIndex < rowcnt; rowIndex++)
	//	{
	//		QTableWidgetItem* item =  m_instTable->item(rowIndex, 0);

	//		char inst[20] = {0}; 
	//		strcpy(inst, item->text().toStdString().c_str());


	//		if (0 == strcmp(inst, poldbar->instru))
	//			item->setCheckState(Qt::Checked);
	//	}


	//}

	vector<Stra2Related> tmp;

	tmp = m_stra2thd1_vbarrltnew;

	m_stra2thd1_vbarrltnew = m_stra2thd1_vbarrltold;

	m_stra2thd1_vbarrltold = tmp;

	//-------------------------------------------------------------------------------------------------------


	/*********************StartCtl*********************************/

	StartCtl(TimerFire_namespace::appreinitfiretimer);

	/**********************************************************************************************/

}

void QtStra2::OnTimer(TimerFire_namespace::TimerFireType timertype)
{
	if (m_thread)
		m_thread->SendTimerData(timertype);
}


void QtStra2::OnctlBtnClicked()
{
	QString str = m_ctlBtn->text();

	if (str == "Start")
	{
		//disable all
		m_instTable->setEnabled(false);
		m_ctlBtn->setEnabled(false);
		m_editBtn->setEnabled(false);
		m_readXmlBtn->setEnabled(false);
		m_writeXmlBtn->setEnabled(false);


		StartCtl();


		m_ctlBtn->setText("End");
		m_ctlBtn->setEnabled(true);
	}
	else if (str == "End")
	{

		m_ctlBtn->setText("Start");
		m_instTable->setEnabled(true);
		m_editBtn->setEnabled(true);
		m_readXmlBtn->setEnabled(true);
		m_writeXmlBtn->setEnabled(true);
	}

}

void QtStra2::OneditBtnClicked()
{
	QtStraInstEdit* QEdit = new QtStraInstEdit(*m_instTable, this);

	if (QEdit->exec())
	{


	}
	
	if (QEdit)
	{
	
		m_instSplitter->insertWidget(0, m_instTable);

		delete QEdit;
	}
		
	

}

void QtStra2::OnreadxmlBtnClicked()
{
	ReadXml();
}

void QtStra2::OnwritexmlBtnClicked()
{
	WriteXml();
}

void QtStra2::OnSlotInit(BarSeries* pBarSer, BarData* pData)
{
	
	pantheios::log_WARNING("[OnSlotInit] ", pData->inst, " index:", panint(pData->index), " tickcnt:", panint(pData->tickcnt));


	QtInstrument* pInst = new QtInstrument(m_strategyinfo, pBarSer, pData);

	if (pInst)
	{
		int index = addTab(pInst, tr(pData->inst));

	}


	if (pData)
		delete pData;

	

		
}

void QtStra2::OnSlotDestroy(BarInfo* pbar)
{
	pantheios::log_WARNING("[OnSlotDestroy] ", pbar->instru);



	
	int tabcnt = count();

	for (int index = 0; index < tabcnt; index++)
	{
		QString text = tabText(index);

		if (string(pbar->instru) == text.toStdString() )
		{
			QtInstrument* pInst = static_cast<QtInstrument*>(widget(index));

			removeTab(index);

			
			if (pInst)
				delete pInst;

			tabcnt = count();
		}
		
	}


}

void QtStra2::OnSlotSysMd(BarData* pData)
{
	//pantheios::log_WARNING("[OnSlotSysMd] ", pData->inst, " index:", panint(pData->index), " tickcnt:", panint(pData->tickcnt));


	int tabcnt = count();

	for (int index = 0; index < tabcnt; index++)
	{
		QString text = tabText(index);

		if (string(pData->inst) == text.toStdString() )
		{
			QtInstrument* pInst = static_cast<QtInstrument*>(widget(index));

			if (pInst)
			{
				pInst->MdUpdate(pData);
			}
		}

	}



	if (pData)
		delete pData;
	

}

void QtStra2::ReadXml()
{
	//first clear
	m_instTable->clear();

	//init row/column cnt and  headlables
	vector<char*> tablehead;
	if (m_xml->GetColumnName(tablehead))
	{
		m_instTable->setRowCount(0);
		m_instTable->setColumnCount(tablehead.size());

		QStringList headerLabels;

		for( vector<char*>::iterator it = tablehead.begin(); it != tablehead.end(); it++)
		{
			headerLabels << *it;
		}

		m_instTable->setHorizontalHeaderLabels(headerLabels);
	}


	//read xml and insert table
	int rowcnt = 0, colcnt = 0;

	if (m_xml->GetRowAndColCnt(rowcnt, colcnt))
	{
		for (int rowIndex = 0; rowIndex < rowcnt; rowIndex++)
		{
			vector < pair<char*, char*> > attriRow;

			//read row from xml
			m_xml->ReadXml(rowIndex, attriRow);

			char destInst[10] = {0};
			if (CStrategySys::ConvertXml(attriRow[0].second, destInst))
			{
				
				int tablerowcnt = m_instTable->rowCount();

				//insert row to table
				m_instTable->insertRow(tablerowcnt);


				//insert column
				for (int colIndex = 0; colIndex < colcnt; colIndex++)
				{
					QTableWidgetItem *item = NULL;

					if (0 == colIndex)
					{
						item = new QTableWidgetItem(destInst);

						item->setCheckState(Qt::Unchecked);
					}
					else
						item = new QTableWidgetItem(attriRow[colIndex].second);

					item->setTextAlignment(Qt::AlignCenter);

					m_instTable->setItem(tablerowcnt, colIndex, item);
				}

			}
			else
			{
				char buf[150] = {0};
				sprintf(buf, "%s (%s)\n" "don't exist in mapPdt.\n", attriRow[0].second, m_xmlfile.c_str());


				int r = QMessageBox::warning(this, tr("TF"),
					tr(buf),
					QMessageBox::Cancel);
			}


		}
	}
	



}

void QtStra2::WriteXml()
{
	// ----------------------1.Clear all xml in memory--------------------------------------------------

	//user may add or remove instrument, so first clear then add them to xml
	if (false == m_xml->ClearXml())
	{
		pantheios::log_ERROR("[QtStra2::WriteXml] ClearXml Error");
		return;
	}

	//m_xml->SaveFile();

	// -----------------------------------------------------------------------------------------------



	// ----------------------2.Insert xml in m_instTable--------------------------------------------------

	int rowcnt = m_instTable->rowCount();

	int colcnt = m_instTable->columnCount();


	for (int rowIndex = 0; rowIndex < rowcnt; rowIndex++)
	{
		vector < pair<char*, char*> > attriRow;


		for (int colIndex = 0; colIndex < colcnt; colIndex++)
		{
			QString strname = m_instTable->horizontalHeaderItem(colIndex)->text();

			QString strvalue = m_instTable->item(rowIndex, colIndex)->text();


			string stdstrname = (strname.toStdString());

			string stdstrvalue = (strvalue.toStdString());


			char* cname = new char[stdstrname.size() + 5]; 
			memcpy(cname, stdstrname.c_str(), stdstrname.size() + 1);

			
			char* cvalue = new char[stdstrvalue.size() + 5];
			memcpy(cvalue, stdstrvalue.c_str(), stdstrvalue.size() + 1);
			

			if ( 0 == colIndex)
			{
				memset(cvalue, 0, stdstrvalue.size() + 5);
				if (CStrategySys::ConvertInst((char*)stdstrvalue.c_str(), cvalue))
				{
					attriRow.push_back( make_pair(cname, cvalue) );
				}
				else
					pantheios::log_ERROR("[QtStra2::WriteXml] ConvertInst Error");

			}
			else
			{
				
				attriRow.push_back( make_pair(cname, cvalue) );
			}
				

		}		


		//write data
		if (false == m_xml->WriteXml(attriRow))
		{
			pantheios::log_ERROR("[QtStra2::WriteXml] WriteXml Error");
		}


		//free memory
		for (vector < pair<char*, char*> >::iterator it = attriRow.begin(); it != attriRow.end(); it++)
		{
			if (it->first)
				delete [] (it->first);

			if (it->second)
				delete [] (it->second);
			
		}

	}


	m_xml->SaveFile();
	// -----------------------------------------------------------------------------------------------


}

void QtStra2::SetVbarrltnew()
{
	//clear new
	m_stra2thd1_vbarrltnew.clear();



	//get count
	int rowcnt = m_instTable->rowCount();
	int colcnt = m_instTable->columnCount();
	//
	//from every row
	for (int rowIndex = 0; rowIndex < rowcnt; rowIndex++)
	{
		Qt::CheckState c = m_instTable->item(rowIndex, 0)->checkState();

		//if checked
		if (Qt::Checked == c)
		{
			char inst[20] = {0}; int reqvol, stopcnt;

			//from every column
			for (int colIndex = 0; colIndex < colcnt; colIndex++)
			{
				QTableWidgetItem* item =  m_instTable->item(rowIndex, colIndex);


				if (0 == colIndex)
					strcpy(inst, item->text().toStdString().c_str());		
				else if (1 == colIndex)
					reqvol = item->text().toInt();
				else if (2 == colIndex)
					stopcnt = item->text().toInt();
			}



			Stra2Related barrlt;
			{
				BarInfo& bar = barrlt.bar;
				strcpy(bar.instru, inst);
				bar.type = tick;
				bar.cnt = 1;
				//barrlt.timertype = timertype;
				userdata_stra2& userdata = barrlt.userdata;
				userdata.vol = reqvol;
				userdata.stopcnt = stopcnt;
			}




			//set new
			m_stra2thd1_vbarrltnew.push_back(barrlt);

		}

	}
}


void QtStra2::StartCtl(TimerFire_namespace::TimerFireType timertype)
{


	/*****************Update m_stra1thd1_vbarrltold and m_stra1thd1_vbarrltnew**********************/

	//change from ui
	if (TimerFire_namespace::invalid == timertype)
	{
		//set old
		m_stra2thd1_vbarrltold = m_stra2thd1_vbarrltnew;


		//set new
		SetVbarrltnew();
	}


	/***************************************************************************************************/


	//1.call member function to calculate Edit/Del/Add Inst
	//2.send data to FrameEvent thread 
	Edit_Del_AddInst(timertype);


	

}

bool QtStra2::DelInst(TimerFire_namespace::TimerFireType timertype, vector<MFCData*>& vpmfcdata)
{

	typedef vector<Stra2Related>::iterator it_vstra2;


	/*****************Update vdel*********************************************/
	for (it_vstra2 itold = m_stra2thd1_vbarrltold.begin(); itold != m_stra2thd1_vbarrltold.end(); itold++)
	{
		BarInfo& oldbar = (*itold).bar;
		userdata_stra2& userdata = (*itold).userdata;
		bool bfound = false;

		for (it_vstra2 itnew = m_stra2thd1_vbarrltnew.begin(); itnew != m_stra2thd1_vbarrltnew.end(); itnew++)
		{
			BarInfo& newbar = (*itnew).bar;
			if (0 == memcmp(&oldbar, &newbar, sizeof(BarInfo)))
			{
				bfound = true;
				break;
			}
		}

		//not found, it's deleted, so add to vpmfcdata for del
		if (false == bfound)
		{
			//new memory
			MFCData* pmfcdata;
			pmfcdata = new MFCData();
			if (NULL == pmfcdata)
			{
				pantheios::log_ERROR("[QtStra2::MFCData_DelInst] pmfcdata(add) NULL");
				return false;
			}

			//set del MFCData info
			pmfcdata->type = MFC_namespace::del;
			memcpy(&pmfcdata->bar, &oldbar, sizeof(BarInfo));//deep copy
			pmfcdata->timertype = timertype;
			pmfcdata->varsize = 0;
			pmfcdata->pvardata = NULL;

			//copy into vpmfcdata
			vpmfcdata.push_back(pmfcdata);
		}

	}

	/************************************************************************/


	return true;

}

bool QtStra2::AddInst(TimerFire_namespace::TimerFireType timertype, vector<MFCData*>& vpmfcdata)
{

	typedef vector<Stra2Related>::iterator it_vstra2;


	/*****************Update vadd*********************************************/
	for (it_vstra2 itnew = m_stra2thd1_vbarrltnew.begin(); itnew != m_stra2thd1_vbarrltnew.end(); itnew++)
	{
		BarInfo& newbar = (*itnew).bar;
		userdata_stra2& userdata =  (*itnew).userdata;
		bool bfound = false;

		for (it_vstra2 itold = m_stra2thd1_vbarrltold.begin(); itold != m_stra2thd1_vbarrltold.end(); itold++)
		{
			BarInfo& oldbar = (*itold).bar;
			if (0 == memcmp(&oldbar, &newbar, sizeof(BarInfo)))
			{
				bfound = true;
				break;
			}
		}

		//not found, it's added, so add to vpmfcdata for add
		if (false == bfound)
		{
			//new memory
			MFCData* pmfcdata;
			pmfcdata = new MFCData();
			if (NULL == pmfcdata)
			{
				pantheios::log_ERROR("[QtStra2::MFCData_AddInst] pmfcdata(add) NULL");
				return false;
			}

			//set add MFCData info
			pmfcdata->type = MFC_namespace::add;
			memcpy(&pmfcdata->bar, &newbar, sizeof(BarInfo));//deep copy
			pmfcdata->timertype = timertype;
			pmfcdata->varsize = sizeof(userdata_stra2);
			pmfcdata->pvardata = (char*)new userdata_stra2();
			if (NULL == pmfcdata->pvardata)//user data is also new
			{
				pantheios::log_ERROR("[QtStra2::MFCData_AddInst] pmfcdata->pvardata(add) NULL");
				return false;
			}
			memcpy(pmfcdata->pvardata, (char*)(&userdata), sizeof(userdata_stra2));//deep copy


			//copy into vpmfcdata
			vpmfcdata.push_back(pmfcdata);

		}

	}
	/************************************************************************/


	return true;

}


bool QtStra2::EditInst(TimerFire_namespace::TimerFireType timertype, vector<MFCData*>& vpmfcdata)
{

	typedef vector<Stra2Related>::iterator it_vstra2;


	/*****************Update vadd*********************************************/
	for (it_vstra2 itnew = m_stra2thd1_vbarrltnew.begin(); itnew != m_stra2thd1_vbarrltnew.end(); itnew++)
	{
		BarInfo& newbar = (*itnew).bar;
		userdata_stra2& new_userdata =  (*itnew).userdata;
		bool bfound = false;

		for (it_vstra2 itold = m_stra2thd1_vbarrltold.begin(); itold != m_stra2thd1_vbarrltold.end(); itold++)
		{
			BarInfo& oldbar = (*itold).bar;
			userdata_stra2& old_userdata =  (*itold).userdata;
			if (0 == memcmp(&oldbar, &newbar, sizeof(BarInfo)))
			{
				if (0 != memcmp(&new_userdata, &old_userdata, sizeof(userdata_stra2)))	//userdata not changed
				{
					bfound = true;
					break;
				}		

			}
		}

		//not found, it's added, so add to vpmfcdata for add
		if (true == bfound)
		{
			//new memory
			MFCData* pmfcdata;
			pmfcdata = new MFCData();
			if (NULL == pmfcdata)
			{
				pantheios::log_ERROR("[QtStra2::MFCData_EditInst] pmfcdata(add) NULL");
				return false;
			}

			//set edit MFCData info
			pmfcdata->type = MFC_namespace::edit;
			memcpy(&pmfcdata->bar, &newbar, sizeof(BarInfo));//deep copy
			pmfcdata->timertype = timertype;
			pmfcdata->varsize = sizeof(userdata_stra2);
			pmfcdata->pvardata = (char*)new userdata_stra2();
			if (NULL == pmfcdata->pvardata)//user data is also new
			{
				pantheios::log_ERROR("[QtStra2::MFCData_EditInst] pmfcdata->pvardata(add) NULL");
				return false;
			}
			memcpy(pmfcdata->pvardata, (char*)(&new_userdata), sizeof(userdata_stra2));//deep copy


			//copy into vpmfcdata
			vpmfcdata.push_back(pmfcdata);

		}

	}
	/************************************************************************/


	return true;

}


void QtStra2::Edit_Del_AddInst(TimerFire_namespace::TimerFireType timertype)
{
	vector<MFCData*> vpmfcdata;


	/*****************Update vpmfcdata with Edit/Del/Add Inst**************/

	if (false == EditInst(timertype, vpmfcdata))
	{
		printf("[Edit_Del_AddInst] EditInst failed\n");
		return;
	}

	if (false == DelInst(timertype, vpmfcdata))
	{
		printf("[Edit_Del_AddInst] DelInst failed\n");
		return;
	}

	if (false == AddInst(timertype, vpmfcdata))
	{
		printf("[Edit_Del_AddInst] AddInst failed\n");
		return;
	}

	/************************************************************************/


	
	//send mfc data
	if (m_thread)
		m_thread->SendMFCData(vpmfcdata);
	



	//delete vpmfcdata 
	typedef vector<MFCData*>::iterator it_vpmfcdata;
	for (it_vpmfcdata itpmfc = vpmfcdata.begin(); itpmfc != vpmfcdata.end() ; itpmfc++)
	{
		MFCData* &pmfcdata = *itpmfc;

		if (pmfcdata)
		{
			delete pmfcdata;
			pmfcdata = NULL;
		}


	}

}
